#ifndef   _FILEFN_H_
#define   _FILEFN_H_

#include "wx/list.h"
#include "wx/arrstr.h"
#include <time.h>

#ifdef __WXWINCE__
// Nothing
#elif !defined(__MWERKS__)
//    #error mmmmm
#include <sys/types.h>
#include <sys/stat.h>
#else
#ifdef __MACH__
#include <sys/types.h>
#include <utime.h>
#include <sys/stat.h>
#include <unistd.h>
#else
#include <stat.h>
#include <unistd.h>
#include <unix.h>
#endif
#endif

#ifdef __OS2__
// need to check for __OS2__ first since currently both
// __OS2__ and __UNIX__ are defined.
#include <process.h>
#include "wx/os2/private.h"
#ifdef __WATCOMC__
#include <direct.h>
#endif
#include <io.h>
#ifdef __EMX__
#include <unistd.h>
#endif
#elif defined(__UNIX__)
#include <unistd.h>
#include <dirent.h>
#endif


#ifdef __BORLANDC__ // Please someone tell me which version of Borland needs
// this (3.1 I believe) and how to test for it.
// If this works for Borland 4.0 as well, then no worries.
#include <dir.h>
#endif

#ifdef __SALFORDC__
#include <dir.h>
#include <unix.h>
#endif

#include  <fcntl.h>       // O_RDONLY &c

#ifdef __WXWINCE__
#else
// define off_t
#if !defined(__WXMAC__) || defined(__UNIX__) || defined(__MACH__)
#include  <sys/types.h>
#else
typedef long off_t;
#endif
#endif

#if (defined(__VISUALC__) && !defined(__WXWINCE__)) || ( defined(__MWERKS__) && defined( __INTEL__) )
typedef _off_t off_t;
#elif defined(__SYMANTEC__)
typedef long off_t;
#elif defined(__MWERKS__) && !defined(__INTEL__) && !defined(__MACH__)
typedef long off_t;
#endif

enum wxSeekMode {
  wxFromStart,
  wxFromCurrent,
  wxFromEnd
};

enum wxFileKind {
  wxFILE_KIND_UNKNOWN,
  wxFILE_KIND_DISK,     // a file supporting seeking to arbitrary offsets
  wxFILE_KIND_TERMINAL, // a tty
  wxFILE_KIND_PIPE      // a pipe
};

// ----------------------------------------------------------------------------
// declare our versions of low level file functions: some compilers prepend
// underscores to the usual names, some also have Unicode versions of them
// ----------------------------------------------------------------------------

// Wrappers around Win32 api functions like CreateFile, ReadFile and such
// Implemented in filefnwce.cpp
#if defined( __WXWINCE__)

#else // Unix or Windows using unknown compiler, assume POSIX supported
typedef off_t wxFileOffset;
#ifdef _LARGE_FILES
#define wxFileOffsetFmtSpec wxLongLongFmtSpec
wxCOMPILE_TIME_ASSERT( sizeof( off_t ) == sizeof( wxLongLong_t ),
                       BadFileSizeType );
// wxFile is present and supports large files
#ifdef wxUSE_FILE
#define wxHAS_LARGE_FILES
#endif
// wxFFile is present and supports large files
#if SIZEOF_LONG == 8 || defined HAVE_FSEEKO
#define wxHAS_LARGE_FFILES
#endif
#ifdef HAVE_FSEEKO
#define wxFseek fseeko
#define wxFtell ftello
#endif
#else
#define wxFileOffsetFmtSpec wxT("")
#endif
// functions
#define   wxClose      close
#define   wxRead       ::read
#define   wxWrite      ::write
#define   wxLseek      lseek
#define   wxSeek       lseek
#define   wxFsync      fsync
#define   wxEof        eof
#define   wxMkDir      mkdir
#define   wxRmDir      rmdir
#define   wxTell(fd)   lseek(fd, 0, SEEK_CUR)
#define   wxStructStat struct stat

#if wxUSE_UNICODE
#define wxNEED_WX_UNISTD_H
#if defined(__DMC__)
typedef unsigned long mode_t;
#endif
int wxStat( const wxChar *file_name, wxStructStat *buf );
int wxLstat( const wxChar *file_name, wxStructStat *buf );
int wxAccess( const wxChar *pathname, int mode );
int wxOpen( const wxChar *pathname, int flags, mode_t mode );
#else
#define   wxOpen       open
#define   wxStat       stat
#define   wxLstat      lstat
#define   wxAccess     access
#endif

#define wxHAS_NATIVE_LSTAT
#endif // platforms

// define wxFseek/wxFtell to large file versions if available (done above) or
// to fseek/ftell if not, to save ifdefs in using code
#ifndef wxFseek
#define wxFseek fseek
#endif
#ifndef wxFtell
#define wxFtell ftell
#endif

#define wxO_BINARY 0

// if the platform doesn't have symlinks, define wxLstat to be the same as
// wxStat to avoid #ifdefs in the code using it
#ifndef wxHAS_NATIVE_LSTAT
    #error mmmm
#define wxLstat wxStat
#endif

const int wxInvalidOffset = -1;
bool wxFileExists( const wxString& filename );
bool wxDirExists( const wxChar *pszPathName );
bool wxIsAbsolutePath( const wxString& filename );
wxChar* wxFileNameFromPath( wxChar *path );
wxString wxFileNameFromPath( const wxString& path );
wxString wxPathOnly( const wxString& path );
wxString wxRealPath( const wxString& path );
void wxDos2UnixFilename( wxChar *s );
void wxUnix2DosFilename( wxChar *s );

// Strip the extension, in situ
void wxStripExtension( wxChar *buffer );
void wxStripExtension( wxString& buffer );

// Get a temporary filename
wxChar* wxGetTempFileName( const wxString& prefix, wxChar *buf = ( wxChar * ) NULL );
bool wxGetTempFileName( const wxString& prefix, wxString& buf );

// Expand file name (~/ and ${OPENWINHOME}/ stuff)
wxChar* wxExpandPath( wxChar *dest, const wxChar *path );
bool wxExpandPath( wxString& dest, const wxChar *path );

// Contract w.r.t environment (</usr/openwin/lib, OPENWHOME> -> ${OPENWINHOME}/lib)
// and make (if under the home tree) relative to home
// [caller must copy-- volatile]
wxChar* wxContractPath( const wxString& filename,
    const wxString& envname = wxEmptyString,
    const wxString& user = wxEmptyString );

// Destructive removal of /./ and /../ stuff
wxChar* wxRealPath( wxChar *path );

// Allocate a copy of the full absolute path
wxChar* wxCopyAbsolutePath( const wxString& path );

// Get first file name matching given wild card.
// Flags are reserved for future use.
#define wxFILE  1
#define wxDIR   2
wxString wxFindFirstFile( const wxChar *spec, int flags = wxFILE );
wxString wxFindNextFile();

// Does the pattern contain wildcards?
bool wxIsWild( const wxString& pattern );

// Does the pattern match the text (usually a filename)?
// If dot_special is true, doesn't match * against . (eliminating
// `hidden' dot files)
bool wxMatchWild( const wxString& pattern,  const wxString& text, bool dot_special = true );

// Concatenate two files to form third
bool wxConcatFiles( const wxString& file1, const wxString& file2, const wxString& file3 );

// Copy file1 to file2
bool wxCopyFile( const wxString& file1, const wxString& file2,
                                  bool overwrite = true );

// Remove file
bool wxRemoveFile( const wxString& file );

// Rename file
bool wxRenameFile( const wxString& file1, const wxString& file2, bool overwrite = true );

// Get current working directory.
// If buf is NULL, allocates space using new, else
// copies into buf.
// IMPORTANT NOTE getcwd is know not to work under some releases
// of Win32s 1.3, according to MS release notes!
wxDEPRECATED( wxChar* wxGetWorkingDirectory( wxChar *buf = ( wxChar * ) NULL, int sz = 1000 ) );
// new and preferred version of wxGetWorkingDirectory
// NB: can't have the same name because of overloading ambiguity
wxString wxGetCwd();

// Set working directory
bool wxSetWorkingDirectory( const wxString& d );

// Make directory
bool wxMkdir( const wxString& dir, int perm = 0777 );

// Remove directory. Flags reserved for future use.
bool wxRmdir( const wxString& dir, int flags = 0 );

// Return the type of an open file
wxFileKind wxGetFileKind( int fd );
wxFileKind wxGetFileKind( FILE *fp );
wxDEPRECATED( inline bool wxPathExists( const wxChar *pszPathName ) );
inline bool wxPathExists( const wxChar *pszPathName ) {
  return wxDirExists( pszPathName );
}

bool wxIsWritable( const wxString &path );
bool wxIsReadable( const wxString &path );
bool wxIsExecutable( const wxString &path );

#define wxFILE_SEP_EXT        wxT('.')
#define wxFILE_SEP_DSK        wxT(':')
#define wxFILE_SEP_PATH_UNIX  wxT('/')
#define wxPATH_SEP_UNIX       wxT(":")
#define wxFILE_SEP_PATH     wxFILE_SEP_PATH_UNIX
#define wxPATH_SEP          wxPATH_SEP_UNIX


#define wxARE_FILENAMES_CASE_SENSITIVE  true

inline bool wxIsPathSeparator( wxChar c ) {
  return c == wxFILE_SEP_PATH;
}

bool wxEndsWithPathSeparator( const wxChar *pszFileName );
void wxSplitPath( const wxChar *pszFileName,wxString *pstrPath,wxString *pstrName,wxString *pstrExt );
bool wxFindFileInPath( wxString *pStr, const wxChar *pszPath, const wxChar *pszFile );
wxString wxGetOSDirectory();

time_t wxFileModificationTime( const wxString& filename );

int wxParseCommonDialogsFilter( const wxString& wildCard, wxArrayString& descriptions, wxArrayString& filters );

class wxUmaskChanger {
  public:
    wxUmaskChanger( int umaskNew ) {
      m_umaskOld = umaskNew == -1 ? -1 : ( int )umask( ( mode_t )umaskNew );
    }

    ~wxUmaskChanger() {
      if( m_umaskOld != -1 ) {
        umask( ( mode_t )m_umaskOld );
      }
    }

  private:
    int m_umaskOld;
};

#define wxCHANGE_UMASK(m) wxUmaskChanger wxMAKE_UNIQUE_NAME(umaskChanger_)(m)

class wxPathList : public wxArrayString {
  public:
    wxPathList() {}
    wxPathList( const wxArrayString &arr ) { Add( arr ); }
    void AddEnvList( const wxString& envVariable );
    bool Add( const wxString& path );
    void Add( const wxArrayString &paths );
    wxString FindValidPath( const wxString& filename ) const;
    wxString FindAbsoluteValidPath( const wxString& filename ) const;
    bool EnsureFileAccessible( const wxString& path );
    wxDEPRECATED( bool Member( const wxString& path ) const );
};

#endif
